#include "BondMsgProcess.h"

#include <core/Utility.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSFIModel.h>
#include <qbprotocol/include/rdProto.h>

#include "../uam/UserAccountManager.h"
#include "qbprotocol/include/SSQBModel.h"

using namespace qb;

namespace {
#define Reg_Func(ID) \
  qbBase::getMessageBond()->RegisterDecodeFunc(ID, qbmsg::bond::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_EX_BEST_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_CFETS_XBOND_QUOTE_QUERY, xQBBestPriceListAck_c);
    DelPtr(E_FID_QB_BOND_FUNDAMENTAL_REQ, xBondFundamentalInfoList_c);
    default:
      break;
  }
  return toDel;
}
}  // namespace

void qbmsg::bond::InitDecodeFuncs() {
  Reg_Func(E_FID_QB_EX_BEST_QUOTE_QUERY);
  Reg_Func(E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY);
  Reg_Func(E_FID_QB_CFETS_XBOND_QUOTE_QUERY);
  Reg_Func(E_FID_QB_BOND_FUNDAMENTAL_REQ);
}

void qbmsg::bond::EncodeFunc(qb::proto::Message& msg, qb::SSRequestMsg* req) {
  char message_type[128] = "";
  switch (req->m_FuncID) {
    case E_FID_QB_SHFI_SINGLE_QUOTE_REQ:  // 上证固收
    case E_FID_QB_SHFI_SINGLE_QUOTE_PUSH:
    case E_FID_QB_SHFI_SINGLE_QUOTE_PUSH_CANCEL: {
      QBSHFIQuoteQuery_t* pdata = (QBSHFIQuoteQuery_t*)req->m_pRequest;
      qb::proto::VariantMap submsg;

      submsg.SetString("BrokerID", pdata->m_BrokerID);
      submsg.SetString("BondKey", pdata->m_BondKey);
      submsg.SetString("ListedMarket", pdata->m_ListedMarket);
      msg.SetMap("xQBSHFIQuoteQuery", submsg);
      FMTBUF(message_type, "%d", req->m_FuncID);
      msg.SetType(message_type);
    } break;

    case E_FID_QB_EX_BEST_QUOTE_QUERY:
    case E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY:
    case E_FID_QB_CFETS_XBOND_QUOTE_QUERY: {  // 50214 查询CFETS X-BOND报价
      qb::proto::Message::List company_id_list;
      qb::proto::Message::List key_list;
      qb::proto::VariantMap submsg;
      QBQuoteQuery_t* pdata = (QBQuoteQuery_t*)req->m_pRequest;
      msg.setString("UserName",
                    SSUserAccountManager::instance()
                        .GetUserInfo()
                        .m_UserAccount);  // 用于查问题时区分用户请求
      msg.setString("IMQ_RequestType", "BONDOFFER_LIST");

      submsg.clear();
      switch (req->m_FuncID) {
        case E_FID_QB_EX_BEST_QUOTE_QUERY:
          submsg.setString("IMQ_CompanyID", "e");
          break;
        default:
          submsg.setString("IMQ_CompanyID", "50");
          break;
      }
      company_id_list.push_back(submsg);
      msg.setList("IMQ_CompanyID", company_id_list);
      for (std::list<TW_BOND>::const_iterator it = pdata->m_Bond.begin();
           it != pdata->m_Bond.end(); ++it) {
        submsg.clear();
        char tmpbuf[41] = {0};
        std::string str = it->m_BondKey;
        str += it->m_ListedMarket;
        submsg.setString("IMQ_Key", str);
        key_list.push_back(submsg);
      }

      msg.setList("IMQ_Key", key_list);
      break;
    }
    case E_FID_QB_BOND_FUNDAMENTAL_REQ: {  // 50054 请求计算器需要的基础数据
      qb::proto::Message::List sublist;
      QBBondFundamentalInfoReq_t* pdata =
          (QBBondFundamentalInfoReq_t*)req->m_pRequest;
      for (std::list<TW_BOND>::const_iterator it = pdata->m_List.begin();
           it != pdata->m_List.end(); ++it) {
        qb::proto::VariantMap listmsg;
        listmsg.setString("Bond_Type", it->m_Bond_Type);
        listmsg.setString("ListedMarket", it->m_ListedMarket);
        listmsg.setString("BondID", it->m_BondID);
        listmsg.setString("BondKey", it->m_BondKey);
        sublist.push_back(listmsg);
      }
      qb::proto::VariantMap submsg;
      submsg.SetList("List", sublist);
      msg.SetMap("xQBBondFundamentalInfoReq", submsg);
      break;
    }
    default:
      break;
  }
}

void* qbmsg::bond::ExtracFunc(int func, const ProtoMessage& msg, void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  switch (func) {
    case E_FID_QB_CFETS_MARKETMAKER_QUOTE_QUERY:
    case E_FID_QB_CFETS_XBOND_QUOTE_QUERY: {  // 50214 查询CFETS X-BOND报价
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xQBBestPriceListAck_c* ptr = new xQBBestPriceListAck_c;
      if (!ptr) return nullptr;

      FIELDCOPY(ptr->m_BusinessCode,
                CParserTool::GetString(msg, "BusinessCode"));

      xQBBestPriceUnit_c bestprice_unit;
      std::string tmp;
      bool verbos = CParserTool::IsVerbosLogEnable();
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&bestprice_unit, 0, sizeof(xQBBestPriceUnit_c));
        tmp.clear();
        const ProtoMap& msgmap = *it;

        // 调整字段的顺序,使得按照名称递增排序来访问,可以达到最高性能
        // 做法:查找	.*\"(\w+)\".*
        //		替换	\1\t\0
        //		选中然后排序
        FIELDCOPY(bestprice_unit.m_bondkey,
                  CParserTool::GetString(msgmap, "bk"));
        FIELDCOPY(bestprice_unit.m_company_id,
                  CParserTool::GetString(msgmap, "cid"));
        // FIELDCOPY(bestprice_unit.m_company_name,
        // CParserTool::GetString(msgmap, "cn"));
        CParserTool::MessageGetTime(msgmap, "ct", bestprice_unit.m_create_time);
        FIELDCOPY(bestprice_unit.m_desc_useless,
                  CParserTool::GetString(msgmap, "desc"));
        FIELDCOPY(bestprice_unit.m_bp_status,
                  CParserTool::GetString(msgmap, "ds"));
        FIELDCOPY(bestprice_unit.m_flag_bad,
                  CParserTool::GetString(msgmap, "fbad"));
        FIELDCOPY(bestprice_unit.m_flag_bargain,
                  CParserTool::GetString(msgmap, "fbar"));
        FIELDCOPY(bestprice_unit.m_fin_company_name,
                  CParserTool::GetString(msgmap, "fcn"));
        FIELDCOPY(bestprice_unit.m_full_price,
                  CParserTool::GetString(msgmap, "fp"));
        FIELDCOPY(bestprice_unit.m_flag_relation,
                  CParserTool::GetString(msgmap, "fr"));
        FIELDCOPY(bestprice_unit.m_flag_vip,
                  CParserTool::GetString(msgmap, "fv"));
        // FIELDCOPY(bestprice_unit.m_bond_code, CParserTool::GetString(msgmap,
        // "gc")); FIELDCOPY(bestprice_unit.m_bond_shorname,
        // CParserTool::GetString(msgmap, "gsn"));
        FIELDCOPY(bestprice_unit.m_id, CParserTool::GetString(msgmap, "id"));
        FIELDCOPY(bestprice_unit.m_trade_clear_Price,
                  CParserTool::GetString(msgmap, "ldnp"));
        FIELDCOPY(bestprice_unit.m_tradePrice,
                  CParserTool::GetString(msgmap, "ldp"));
        FIELDCOPY(bestprice_unit.m_listedmarket,
                  CParserTool::GetString(msgmap, "lm"));
        CParserTool::MessageGetTime(msgmap, "mt", bestprice_unit.m_modify_time);
        FIELDCOPY(bestprice_unit.m_clean_price,
                  CParserTool::GetString(msgmap, "np"));
        FIELDCOPY(bestprice_unit.m_price_description,
                  CParserTool::GetString(msgmap, "pdesc"));
        FIELDCOPY(bestprice_unit.m_price,
                  CParserTool::GetString(msgmap, "pri"));
        FIELDCOPY(bestprice_unit.m_price_status,
                  CParserTool::GetString(msgmap, "ps"));
        FIELDCOPY(bestprice_unit.m_quotetype,
                  CParserTool::GetString(msgmap, "qt"));
        FIELDCOPY(bestprice_unit.m_rebate,
                  CParserTool::GetString(msgmap, "reb"));
        FIELDCOPY(bestprice_unit.m_return_point,
                  CParserTool::GetString(msgmap, "rp"));
        FIELDCOPY(bestprice_unit.m_status,
                  CParserTool::GetString(msgmap, "sts"));
        FIELDCOPY(bestprice_unit.m_symbol,
                  CParserTool::GetString(msgmap, "sym"));
        msgmap.GetInt32("ver", bestprice_unit.m_version);
        FIELDCOPY(bestprice_unit.m_volume,
                  CParserTool::GetString(msgmap, "vol"));
        FIELDCOPY(bestprice_unit.m_yield, CParserTool::GetString(msgmap, "yd"));

        ptr->m_List.push_back(bestprice_unit);

        // 			if (verbos)
        // 			{
        // 				CTime T0(bestprice_unit.m_create_time);
        // 				CTime T1(bestprice_unit.m_modify_time);
        // 				ss::base::SArgument	args[] = {
        // 					T0.GetYear(), T0.GetMonth(),
        // T0.GetDay(), T0.GetHour(), T0.GetMinute(), T0.GetSecond(),
        // 					T1.GetYear(), T1.GetMonth(),
        // T1.GetDay(), T1.GetHour(), T1.GetMinute(), T1.GetSecond(),
        // 					/*bestprice_unit.m_bond_code,
        // bestprice_unit.m_bond_shorname,*/ bestprice_unit.m_company_id,
        // /*bestprice_unit.m_company_name,*/ 					bestprice_unit.m_symbol,
        // bestprice_unit.m_version, bestprice_unit.m_price,
        // bestprice_unit.m_volume, bestprice_unit.m_bp_status,
        // bestprice_unit.m_rebate, bestprice_unit.m_price_status
        // 				};
        // 				logvec(BL_DBUG,
        // "BestPrice--CreateTime={0}-{1}-{2} {3}:{4}:{5},ModifyTime={6}-{7}-{8}
        // {9}:{10}:{11},BrokerID={12},Symbol(1-bid)={13},Version={14},Price={15},Vol={16},deal_status={17},Rebate={18},price_status={19}",
        // args, _countof(args));
        // 			}
      }

      ProtoMap extrmsgmap;
      if (msg.GetMap("IMQ_EXTRAINFO", extrmsgmap)) {
        ProtoList extrmsglist;
        if (extrmsgmap.getList("Version_List", extrmsglist)) {
          xQBBestPriceVersionUnit_c version_unit;
          for (ProtoList::const_iterator it = extrmsglist.begin();
               it != extrmsglist.end(); ++it) {
            if (it->Type != ProtoValue::VAR_MAP) continue;

            memset(&version_unit, 0, sizeof(xQBBestPriceVersionUnit_c));
            const ProtoMap& msgmap = *it;

            FIELDCOPY(version_unit.m_company_id,
                      CParserTool::GetString(msgmap, "BF_CompanyID"));
            msgmap.GetInt32("BF_Version", version_unit.m_version);

            ptr->m_extList.push_back(version_unit);
          }
        }
      }
      return ptr;
      break;
    }
    case E_FID_QB_BOND_FUNDAMENTAL_REQ: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xBondFundamentalInfoList_c* ptr = new xBondFundamentalInfoList_c;
      if (!ptr) return nullptr;

      xBondFundamentalInfo_c fundinfo_unit;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&fundinfo_unit, 0, sizeof(xBondFundamentalInfo_c));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(fundinfo_unit.m_Bond_Key,
                  CParserTool::GetString(msgmap, "Bond_Key"));
        FIELDCOPY(fundinfo_unit.m_ListedMarket,
                  CParserTool::GetString(msgmap, "ListedMarket"));
        FIELDCOPY(fundinfo_unit.m_Bond_ID,
                  CParserTool::GetString(msgmap, "Bond_ID"));
        FIELDCOPY(fundinfo_unit.m_BondSubtype,
                  CParserTool::GetString(msgmap, "BondSubtype"));
        FIELDCOPY(fundinfo_unit.m_ExternalType,
                  CParserTool::GetString(msgmap, "ExternalType"));
        FIELDCOPY(fundinfo_unit.m_Interest_Start_Date,
                  CParserTool::GetString(msgmap, "Interest_Start_Date"));
        FIELDCOPY(fundinfo_unit.m_Maturity_Date,
                  CParserTool::GetString(msgmap, "Maturity_Date"));
        FIELDCOPY(fundinfo_unit.m_First_Coupon_Date,
                  CParserTool::GetString(msgmap, "First_Coupon_Date"));
        FIELDCOPY(fundinfo_unit.m_Option_Type,
                  CParserTool::GetString(msgmap, "Option_Type"));
        FIELDCOPY(fundinfo_unit.m_Option_Style,
                  CParserTool::GetString(msgmap, "Option_Style"));
        msgmap.GetInt32("Call_No", fundinfo_unit.m_Call_No);
        FIELDCOPY(fundinfo_unit.m_Call_Str,
                  CParserTool::GetString(msgmap, "Call_Str"));
        msgmap.GetInt32("Put_No", fundinfo_unit.m_Put_No);
        FIELDCOPY(fundinfo_unit.m_Put_Str,
                  CParserTool::GetString(msgmap, "Put_Str"));
        FIELDCOPY(fundinfo_unit.m_First_Exchg_Bond_Key,
                  CParserTool::GetString(msgmap, "First_Exchg_Bond_Key"));
        msgmap.GetInt32("First_Exchg_No", fundinfo_unit.m_First_Exchg_No);
        FIELDCOPY(fundinfo_unit.m_First_Exchg_Str,
                  CParserTool::GetString(msgmap, "First_Exchg_Str"));
        msgmap.GetInt32("Sec_Exchg_No", fundinfo_unit.m_Sec_Exchg_No);
        FIELDCOPY(fundinfo_unit.m_Sec_Exchg_Year,
                  CParserTool::GetString(msgmap, "Sec_Exchg_Year"));
        FIELDCOPY(fundinfo_unit.m_Assign_Trans_Key,
                  CParserTool::GetString(msgmap, "Assign_Trans_Key"));
        msgmap.GetInt32("Assign_Trans_No", fundinfo_unit.m_Assign_Trans_No);
        FIELDCOPY(fundinfo_unit.m_Assign_Trans_Str,
                  CParserTool::GetString(msgmap, "Assign_Trans_Str"));
        FIELDCOPY(fundinfo_unit.m_Compensate_Rate,
                  CParserTool::GetString(msgmap, "Compensate_Rate"));
        msgmap.GetInt32("Compensate_From", fundinfo_unit.m_Compensate_From);
        FIELDCOPY(fundinfo_unit.m_Option_Exercise,
                  CParserTool::GetString(msgmap, "Option_Exercise"));
        FIELDCOPY(fundinfo_unit.m_Option_Exercise_Date,
                  CParserTool::GetString(msgmap, "Option_Exercise_Date"));
        FIELDCOPY(fundinfo_unit.m_Coupon_Type,
                  CParserTool::GetString(msgmap, "Coupon_Type"));
        msgmap.GetDouble("Coupon_Rate_Spread",
                         fundinfo_unit.m_Coupon_Rate_Spread);
        msgmap.GetDouble("Coupon_Rate_Current",
                         fundinfo_unit.m_Coupon_Rate_Current);
        FIELDCOPY(fundinfo_unit.m_Coupon_Frequency,
                  CParserTool::GetString(msgmap, "Coupon_Frequency"));
        FIELDCOPY(fundinfo_unit.m_Compound_Frequency,
                  CParserTool::GetString(msgmap, "Compound_Frequency"));
        FIELDCOPY(fundinfo_unit.m_Interest_Basis,
                  CParserTool::GetString(msgmap, "Interest_Basis"));
        FIELDCOPY(fundinfo_unit.m_Coupon_Dist,
                  CParserTool::GetString(msgmap, "Coupon_Dist"));
        msgmap.GetDouble("FRN_Multiplier", fundinfo_unit.m_FRN_Multiplier);
        FIELDCOPY(fundinfo_unit.m_FRN_Index_ID,
                  CParserTool::GetString(msgmap, "FRN_Index_ID"));
        msgmap.GetDouble("First_Index_Rate", fundinfo_unit.m_First_Index_Rate);
        FIELDCOPY(fundinfo_unit.m_Fixing_Frequency,
                  CParserTool::GetString(msgmap, "Fixing_Frequency"));
        msgmap.GetInt32("Fixing_MA_Days", fundinfo_unit.m_Fixing_MA_Days);
        FIELDCOPY(fundinfo_unit.m_Fixing_Preceds,
                  CParserTool::GetString(msgmap, "Fixing_Preceds"));
        FIELDCOPY(fundinfo_unit.m_Fixing_Calendar_Key,
                  CParserTool::GetString(msgmap, "Fixing_Calendar_Key"));
        FIELDCOPY(fundinfo_unit.m_Fixing_Tailing,
                  CParserTool::GetString(msgmap, "Fixing_Tailing"));
        msgmap.GetInt32("Fixing_Digit", fundinfo_unit.m_Fixing_Digit);
        FIELDCOPY(fundinfo_unit.m_Reset_Effective,
                  CParserTool::GetString(msgmap, "Reset_Effective"));
        msgmap.GetDouble("Cap", fundinfo_unit.m_Cap);
        msgmap.GetDouble("Flr", fundinfo_unit.m_Flr);
        FIELDCOPY(fundinfo_unit.m_Simple_Compound,
                  CParserTool::GetString(msgmap, "Simple_Compound"));
        FIELDCOPY(fundinfo_unit.m_Variable_Schedule,
                  CParserTool::GetString(msgmap, "Variable_Schedule"));
        FIELDCOPY(fundinfo_unit.m_Coupon_Day_Adjust,
                  CParserTool::GetString(msgmap, "Coupon_Day_Adjust"));
        FIELDCOPY(fundinfo_unit.m_Coupon_Day_DMC,
                  CParserTool::GetString(msgmap, "Coupon_Day_DMC"));
        FIELDCOPY(fundinfo_unit.m_Coupon_Calendar_Key,
                  CParserTool::GetString(msgmap, "Coupon_Calendar_Key"));
        FIELDCOPY(fundinfo_unit.m_Pricing_Conv,
                  CParserTool::GetString(msgmap, "Pricing_Conv"));
        msgmap.GetDouble("Issue_Price", fundinfo_unit.m_Issue_Price);
        msgmap.GetInt32("Redemption_No", fundinfo_unit.m_Redemption_No);
        FIELDCOPY(fundinfo_unit.m_Redemption_Str,
                  CParserTool::GetString(msgmap, "Redemption_Str"));
        FIELDCOPY(fundinfo_unit.m_Maturity_Adjust,
                  CParserTool::GetString(msgmap, "Maturity_Adjust"));
        FIELDCOPY(fundinfo_unit.m_Maturity_DMC,
                  CParserTool::GetString(msgmap, "Maturity_DMC"));
        FIELDCOPY(fundinfo_unit.m_Maturity_Calendar_Key,
                  CParserTool::GetString(msgmap, "Maturity_Calendar_Key"));
        FIELDCOPY(fundinfo_unit.m_Listed_Date,
                  CParserTool::GetString(msgmap, "Listed_Date"));
        FIELDCOPY(fundinfo_unit.m_IssuerCode,
                  CParserTool::GetString(msgmap, "IssuerCode"));
        ptr->m_List.push_back(fundinfo_unit);
      }
      return ptr;
      break;
    }
    default:
      break;
  }
  return nullptr;
}
